﻿#region using...
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
#endregion

namespace Infusion.Silverlight.Controls.Ribbon
{
    #region Delegates...
    public delegate void ColumnWidthChangedEventHandler(object sender, ColumnWidthChangedEventArgs e);
    #endregion

    #region : RibbonTabGroupDialog :
    public enum RibbonTabGroupDialog
    {
        Hidden,
        Enabled,
        Disabled
    }
    #endregion

    #region : RibbonTabGroupRows :
    public enum RibbonTabGroupRows
    {
        Three = 3,
        Two = 2
    }
    #endregion

    #region : RibbonTabGroupItemRowSpan :
    public enum RibbonTabGroupItemRowSpan
    {
        One = 1,
        Two = 2,
        Three = 3
    }
    #endregion

    #region : RibbonTabGroup :
    #region Template Parts...
    [TemplatePart(Name = RibbonTabGroup.RibbonTabGroupLayoutRoot, Type = typeof(Canvas))]
    [TemplatePart(Name = RibbonTabGroup.TxtTitle, Type = typeof(TextBlock))]
    [TemplatePart(Name = RibbonTabGroup.CanvasBody, Type = typeof(Canvas))]
    [TemplatePart(Name = RibbonTabGroup.GridBodyLayout, Type = typeof(Grid))]
    [TemplatePart(Name = RibbonTabGroup.GridLayout, Type = typeof(Grid))]
    [TemplatePart(Name = RibbonTabGroup.GridTitle, Type = typeof(Grid))]
    [TemplatePart(Name = RibbonTabGroup.RectLayoutClip, Type = typeof(Rectangle))]
    [TemplatePart(Name = RibbonTabGroup.RectBorder, Type = typeof(Rectangle))]
    [TemplatePart(Name = RibbonTabGroup.StoryboardCanvasHighlight, Type = typeof(Storyboard))]
    #endregion
    [ContentProperty("Items")]
    public class RibbonTabGroup : Control
    {
        #region Events...
        public event ColumnWidthChangedEventHandler ColumnWidthChanged;
        #endregion

        #region TemplatePart Names...
        public const string RibbonTabGroupLayoutRoot = "RibbonTabGroupLayoutRoot";
        public const string TxtTitle = "TxtTitle";
        public const string CanvasBody = "CanvasBody";
        public const string GridBodyLayout = "GridBodyLayout";
        public const string GridLayout = "GridLayout";
        public const string GridTitle = "GridTitle";
        public const string RectLayoutClip = "RectLayoutClip";
        public const string RectBorder = "RectBorder";
        public const string StoryboardCanvasHighlight = "StoryboardCanvasHighlight";
        #endregion

        #region TemplatePart Variables...
        internal Canvas ribbonTabGroupLayoutRoot;
        internal TextBlock txtTitle;
        internal Canvas canvasBody;
        internal Grid gridBodyLayout;
        internal Grid gridLayout;
        internal Grid gridTitle;
        internal RectangleGeometry rectLayoutClip;
        internal Rectangle rectBorder;
        internal Storyboard storyboardCanvasHighlight;
        #endregion

        #region Class Variables...
        private bool templateApplied = false;
        private bool dirtyLayout = false;
        private RibbonTab parentRibbonTab;
        #endregion

        #region Dependency Properties...
        #region ItemsProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonTabGroup.Items dependency property.
        /// </summary>
        public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
                "Items",
                typeof(ItemsCollection),
                typeof(RibbonTabGroup),
                null);
        #endregion

        #region TitleProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonTabGroup.Title dependency property.
        /// </summary>
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            "Title",
            typeof(string),
            typeof(RibbonTabGroup),
            new PropertyMetadata(new PropertyChangedCallback(TitlePropertyChanged)));
        #endregion

        #region DialogProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonTabGroup.Dialog dependency property.
        /// </summary>
        public static readonly DependencyProperty DialogProperty = DependencyProperty.Register(
            "Dialog",
            typeof(RibbonTabGroupDialog),
            typeof(RibbonTabGroup),
            new PropertyMetadata(new PropertyChangedCallback(DialogPropertyChanged)));
        #endregion

        #region RowsProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonTabGroup.Rows dependency property.
        /// </summary>
        public static readonly DependencyProperty RowsProperty = DependencyProperty.Register(
            "Rows",
            typeof(RibbonTabGroupRows),
            typeof(RibbonTabGroup),
            null);
        #endregion
        #endregion

        #region Dependency Property Changed Handlers...
        #region TitlePropertyChanged
        private static void TitlePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            if (args.NewValue != null)
            {
                RibbonTabGroup group = (RibbonTabGroup)obj;

                if (group.txtTitle != null)
                    group.txtTitle.Text =args.NewValue.ToString();
            }
            else
            {
                throw new ArgumentNullException("Title can not be null or an empty string.");
            }
        }
        #endregion

        #region DialogPropertyChanged
        private static void DialogPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
        }
        #endregion
        #endregion

        #region Constructor(s)...
        #region RibbonTabGroup
        public RibbonTabGroup() : base()
        {
            DefaultStyleKey = typeof(RibbonTabGroup);

            Items = new ItemsCollection();
            Rows = RibbonTabGroupRows.Three;
        }
        #endregion
        #endregion

        #region Event Handlers...
        #region ribbonTabGroupItem_SizeChanged
        private void ribbonTabGroupItem_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            dirtyLayout = true;

            Dictionary<int, double> columnWidths = new Dictionary<int, double>();

            foreach (FrameworkElement element in Items)
            {
                int columnIndex = (int)element.GetValue(Grid.ColumnProperty);

                double thisWidth;
                if (element is RibbonTabGroupItem)
                    thisWidth = ((RibbonTabGroupItem)element).RealWidth;
                else
                    thisWidth = (double)element.ActualWidth;

                if (columnWidths.ContainsKey(columnIndex))
                {
                    if (columnWidths[columnIndex] < thisWidth)
                        columnWidths[columnIndex] = thisWidth;
                }
                else
                {
                    columnWidths.Add(columnIndex, thisWidth);
                }
            }

            for (int columnIndex = 0; columnIndex < gridBodyLayout.ColumnDefinitions.Count; columnIndex++)
            {
                gridBodyLayout.ColumnDefinitions[columnIndex].Width = new GridLength(columnWidths[columnIndex]);
                
                if (ColumnWidthChanged != null)
                    ColumnWidthChanged(this, new ColumnWidthChangedEventArgs(columnIndex, gridBodyLayout.ColumnDefinitions[columnIndex].Width));
            }
        }
        #endregion

        #region ribbonTabGroupLayoutRoot_MouseLeave
        private void ribbonTabGroupLayoutRoot_MouseLeave(object sender, MouseEventArgs e)
        {
            ((ColorAnimation)storyboardCanvasHighlight.Children[0]).To = Colors.Transparent;
            ((ColorAnimation)storyboardCanvasHighlight.Children[1]).To = Helper.HexToColor("#DFE3EF");
            ((ColorAnimation)storyboardCanvasHighlight.Children[2]).To = Helper.HexToColor("#C3C7D1");
            storyboardCanvasHighlight.Begin();
        }
        #endregion

        #region ribbonTabGroupLayoutRoot_MouseEnter
        private void ribbonTabGroupLayoutRoot_MouseEnter(object sender, MouseEventArgs e)
        {
            if (!ParentRibbonTab.ParentRibbon.HasMenuOpen)
            {
                ((ColorAnimation)storyboardCanvasHighlight.Children[0]).To = Helper.HexToColor("#7FFFFFFF");
                ((ColorAnimation)storyboardCanvasHighlight.Children[1]).To = Helper.HexToColor("#DEE2EE");
                ((ColorAnimation)storyboardCanvasHighlight.Children[2]).To = Helper.HexToColor("#B3B9C7");
                storyboardCanvasHighlight.Begin();
            }
        }
        #endregion

        #region ribbonTabGroupLayoutRoot_LayoutUpdated
        private void ribbonTabGroupLayoutRoot_LayoutUpdated(object sender, EventArgs e)
        {
            if (dirtyLayout)
            {
                double width = gridBodyLayout.ActualWidth + 6;

                ribbonTabGroupLayoutRoot.Width = width;
                rectLayoutClip.Rect = new Rect(0, 0, width, rectLayoutClip.Rect.Height);
                gridLayout.ColumnDefinitions[0].Width = new GridLength(width);
                gridTitle.ColumnDefinitions[0].Width = new GridLength(width - (Dialog == RibbonTabGroupDialog.Hidden ? 0 : 18));
                gridTitle.ColumnDefinitions[1].Width = new GridLength(Dialog != RibbonTabGroupDialog.Hidden ? 18 : 0);
                rectBorder.Width = width + 1;

                dirtyLayout = false;
            }
        }
        #endregion
        #endregion

        #region Methods...
        #region OnApplyTemplate
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (!templateApplied)
            {
                ribbonTabGroupLayoutRoot = (Canvas)GetTemplateChild(RibbonTabGroupLayoutRoot);
                txtTitle = (TextBlock)GetTemplateChild(TxtTitle);
                canvasBody = (Canvas)GetTemplateChild(CanvasBody);
                gridBodyLayout = (Grid)GetTemplateChild(GridBodyLayout);
                storyboardCanvasHighlight = (Storyboard)GetTemplateChild(StoryboardCanvasHighlight);
                gridLayout = (Grid)GetTemplateChild(GridLayout);
                gridTitle = (Grid)GetTemplateChild(GridTitle);
                rectLayoutClip = (RectangleGeometry)GetTemplateChild(RectLayoutClip);
                rectBorder = (Rectangle)GetTemplateChild(RectBorder);

                ribbonTabGroupLayoutRoot.MouseEnter += new MouseEventHandler(ribbonTabGroupLayoutRoot_MouseEnter);
                ribbonTabGroupLayoutRoot.MouseLeave += new MouseEventHandler(ribbonTabGroupLayoutRoot_MouseLeave);
                ribbonTabGroupLayoutRoot.LayoutUpdated += new EventHandler(ribbonTabGroupLayoutRoot_LayoutUpdated);

                txtTitle.Text = Title;

                int columnIndex = 0;
                int rowIndex = 0;

                if (Rows == RibbonTabGroupRows.Two)
                {
                    gridBodyLayout.RowDefinitions.RemoveAt(2);
                    gridBodyLayout.RowDefinitions[0].Height = new GridLength(33);
                    gridBodyLayout.RowDefinitions[1].Height = new GridLength(33);
                }

                for (int itemIndex = 0; itemIndex < Items.Count; itemIndex++)
                {
                    if (gridBodyLayout.ColumnDefinitions.Count - 1 < columnIndex)
                    {
                        gridBodyLayout.ColumnDefinitions.Add(Helper.CreateGridColumnDefinition(0, GridUnitType.Auto));
                    }

                    Items[itemIndex].HorizontalAlignment = HorizontalAlignment.Left;
                    Items[itemIndex].SetValue(Grid.ColumnProperty, columnIndex);
                    Items[itemIndex].SetValue(Grid.RowProperty, rowIndex);

                    if (Items[itemIndex] is IRibbonTabGroupItem)
                    {
                        IRibbonTabGroupItem item = (IRibbonTabGroupItem)Items[itemIndex];
                        item.ParentRibbonTabGroup = this;

                        if (item is RibbonButton)
                            ((RibbonButton)item).ParentRibbon = item.ParentRibbonTabGroup.ParentRibbonTab.ParentRibbon;

                        int rowSpan = (int)item.RibbonTabGroupItemRowSpan;
                        Items[itemIndex].SetValue(Grid.RowSpanProperty, rowSpan);

                        if (rowSpan > 1)
                            rowIndex += rowSpan - 1;
                    }

                    if (Rows == RibbonTabGroupRows.Two) //&& rowIndex == 0)
                    {
                        Items[itemIndex].Margin = new Thickness(Items[itemIndex].Margin.Left,
                            (rowIndex == 0 ? 7 : 1),
                            Items[itemIndex].Margin.Right,
                            Items[itemIndex].Margin.Bottom);
                    }
                    
                    rowIndex++;

                    gridBodyLayout.Children.Add(Items[itemIndex]);

                    if (rowIndex > ((int)Rows) - 1)
                    {
                        columnIndex++;
                        rowIndex = 0;
                    }

                    Items[itemIndex].SizeChanged += new SizeChangedEventHandler(ribbonTabGroupItem_SizeChanged);
                }

                dirtyLayout = true;
                templateApplied = true;
            }
        }
        #endregion
        #endregion

        #region Properties...
        #region Items
        public ItemsCollection Items
        {
            get { return (ItemsCollection)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }
        #endregion

        #region ParentRibbonTab
        public RibbonTab ParentRibbonTab
        {
            get { return parentRibbonTab; }
            set { parentRibbonTab = value; }
        }
        #endregion

        #region Title
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        #endregion

        #region Dialog
        public RibbonTabGroupDialog Dialog
        {
            get { return (RibbonTabGroupDialog)GetValue(DialogProperty); }
            set { SetValue(DialogProperty, value); }
        }
        #endregion

        #region Rows
        public RibbonTabGroupRows Rows
        {
            get { return (RibbonTabGroupRows)GetValue(RowsProperty); }
            set { SetValue(RowsProperty, value); }
        }
        #endregion
        #endregion
    }
    #endregion

    #region : ItemsCollection :
    public class ItemsCollection : ObservableCollection<FrameworkElement>
    {
    }
    #endregion

    #region : ColumnWidthChangedEventArgs :
    public class ColumnWidthChangedEventArgs : EventArgs
    {
        #region Class Variables...
        private int columnIndex;
        private GridLength newWidth;
        #endregion

        #region Constructor(s)...
        #region ColumnWidthChangedEventArgs
        public ColumnWidthChangedEventArgs(int columnIndex, GridLength newWidth)
        {
            this.columnIndex = columnIndex;
            this.newWidth = newWidth;
        }
        #endregion
        #endregion

        #region Properties...
        #region ColumnIndex
        public int ColumnIndex
        {
            get { return columnIndex; }
        }
        #endregion

        #region NewWidth
        public GridLength NewWidth
        {
            get { return newWidth; }
        }
        #endregion
        #endregion
    }
    #endregion
}